Skip to content

ci(gui): stop pnpm side-effects cache poisoning of Electron installs - #4

Merged
PAMulligan merged 1 commit into
mainfrom
ci/gui-electron-cache-poisoning
Jul 7, 2026
Merged

ci(gui): stop pnpm side-effects cache poisoning of Electron installs#4
PAMulligan merged 1 commit into
mainfrom
ci/gui-electron-cache-poisoning

Conversation

@PAMulligan

Copy link
Copy Markdown
Contributor

Problem

The GUI smoke lane fails on CI with:

electron.launch: Electron failed to install correctly, please delete node_modules/electron and try installing again

Root cause

A poisoned shared pnpm store cache — not a flaky download:

  1. Both jobs in gui.yml (and the ubuntu release build in gui-release.yml) share one pnpm store cache via setup-node's cache: pnpm, keyed only on OS/arch + pnpm-lock.yaml hash.
  2. The fast gui job deliberately installs with ELECTRON_SKIP_BINARY_DOWNLOAD=1. Electron's postinstall runs but downloads nothing — and pnpm's side-effects cache (on by default) records that binary-less postinstall result in the store.
  3. The fast job finishes first and wins the immutable cache save.
  4. On the next run, the smoke job restores the poisoned store and pnpm replays the recorded postinstall instead of running it. node_modules/electron/dist never appears → electron.launch throws.

This also explains why the lane passed at first (cache miss → real install) and broke later with no GUI change.

Fix

Pass --config.side-effects-cache=false at all three install sites:

  • gui.yml gui job — stops writing the poisoned entry at the source
  • gui.yml smoke job — stops reading any existing poisoned entry; required for CI to pass immediately, since the bad cache entry for the current lockfile hash is already saved and immutable
  • gui-release.yml — the ubuntu runner shares the same cache key and runs the same smoke test

Trade-off: these jobs re-run postinstalls each time (the smoke job re-downloads the ~100 MB Electron binary per run) instead of replaying them; package tarball caching is unaffected. No manual cache eviction needed.

Verification

Reproduced and verified locally on pnpm 9.15.0 (the version CI pins via Corepack) with a minimal fake package whose postinstall skips creating its "binary" under ELECTRON_SKIP_BINARY_DOWNLOAD:

  • install with the env var, then a clean env-free install through the same store → postinstall silently replayed, binary missing (the CI failure)
  • same again with --config.side-effects-cache=false --frozen-lockfile → postinstall really ran, binary present

Both workflow files parse as valid YAML.

🤖 Generated with Claude Code

The gui (lint/typecheck) job installs with ELECTRON_SKIP_BINARY_DOWNLOAD=1,
and pnpm's side-effects cache (default on) records that binary-less Electron
postinstall in the pnpm store. setup-node caches the store keyed only on
OS + lockfile hash, and the fast job wins the immutable cache save — so the
smoke job (and the Linux release build) restores the poisoned store, pnpm
replays the recorded postinstall instead of running it, node_modules/electron
never gets dist/, and electron.launch dies with "Electron failed to install
correctly".

Pass --config.side-effects-cache=false at all three install sites: the gui
job stops writing the poisoned entry, and the smoke/release installs stop
trusting any existing one (the already-saved cache entry is immutable until
the lockfile changes, so fixing only the producer would not unbreak CI).

Verified with a local repro on pnpm 9.15.0: a fake package whose postinstall
skips its binary under the env var; a second env-free install through the
same store silently replayed the skip, and the flag made it really run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@PAMulligan
PAMulligan merged commit d1a910b into main Jul 7, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant